<?php
class Gi_Sql_Writer {
  private $_sql = null;
  /**
  * @desc Crea el objeto
  * @param string tipo de sentencia uede select insert o update por default sera select
  */
  public function __construct ($type, $table, $fields) {
    $type = strtolower($type);
    if ($type == "insert")
      $this->get_insert($table, $fields);
    elseif ($type == "select") 
      $this->get_select($table, $fields);
    elseif($type == "update")
      $this->get_update($table, $fields);
    else 
      throw new Exception("Not Implemented");
  }
  
  public function __toString () {
    return $this->_sql;
  }

  public function add_where($where,$op = 'AND', $b_add = true) {
    if (!$b_add) {
      return $this;
    }
    $sql = $this->_sql;
    $where = "( $where )";
    $tiene_where = strpos($sql,'WHERE');
    $tiene_order = strpos($sql,'ORDER BY');
    $tiene_group = strpos($sql,'GROUP BY');

    if ($tiene_where) {
      $where = " $op ".$where.' ';
    }
    else {
      $where = ' WHERE '.$where.' ';
    }

    if ($tiene_group) {
      $sql = substr_replace($sql,$where,$tiene_group,0);
    }
    elseif ($tiene_order) {
      $sql = substr_replace($sql,$where,$tiene_order,0);
    }
    else {
      $sql .= $where;
    }
    $this->_sql = $sql;
    return $this;
  }
  
  function add_join($type, $table, $alias = null, $cond, $b_add = true) {
    if (!$b_add) {
      return $this;
    }
    $sql = $this->_sql; 
    $type = strtoupper($type);  
    $join = " $type " . "JOIN". " " . "$table" . " " . "$alias" . " ON " . "$cond";
      //antes del WHERE
    $tiene_where = strpos($sql,'WHERE');
    $tiene_order = strpos($sql,'ORDER BY');
      
    if ($tiene_where) {
      $sql = substr_replace($sql,$join.' ',$tiene_where,0);
    }
    elseif ($tiene_order) {
      $sql = substr_replace($sql,$join.' ',$tiene_order,0);    
    }   
    $sql .= $join;
    $this->_sql = $sql;
    return $this;
  }
  
  function add_limit($start,$b_add = true) {
     if (!$b_add) {
      return $this;
    }
    $sql = $this->_sql; 
    $tiene_limit = strpos($sql,'LIMIT');
     
    if ($tiene_limit) {
      $sql = ereg_replace('LIMIT .*$','',$sql);
    }

    $sql .= " LIMIT $start";
    $this->_sql = $sql;
    return $this;
  }
  
  function add_distinct($b_add=true) {
    if (!$b_add) {
      return $this;
    }
    $sql = $this->_sql; 
    $tiene_distinct = strpos($sql,'DISTINCT');      
    if (!$tiene_distinct) {
      $sql = ereg_replace('^SELECT ','SELECT DISTINCT ',$sql);      
    }  
    $this->_sql = $sql;
    return $this;
  }
  
  function add_having($where, $b_add = true, $op = 'AND') {
    if (!$b_add) {
      return $this;
    }
    $sql = $this->_sql;  
    $where = "( $where )";
    $tiene_having = strpos($sql,'HAVING');
    $tiene_order = strpos($sql,'ORDER BY');
    $tiene_group = strpos($sql,'GROUP BY');

    if ($tiene_having) {
      $where = " $op ".$where.' ';
    }
    else {
      $where = ' HAVING '.$where.' ';
    }

    if ($tiene_order) {
      $sql = substr_replace($sql,$where,$tiene_order,0);
    }
    else {
      $sql .= $where;
    }
    $this->_sql = $sql;
    return $this;
  }
  
  function add_order($order, $b_add = true) {
    if (!$b_add) {
      return $this;
    } 
    $sql = $this->_sql;

    $tiene_order = strpos($sql,'ORDER BY');
    $tiene_limit = strpos($sql,'LIMIT');

    if (!$order && $tiene_order) {
      $sql = preg_replace('/ORDER BY (.*?)(LIMIT.*?)?$/is',"\\2",$sql);
    }
    elseif ($tiene_order) {
      $sql = preg_replace('/ORDER BY (.*?)(LIMIT.*?)?$/is',"ORDER BY $order \\2",$sql);    
    }
    elseif (!$tiene_order && $tiene_limit) {
      $sql = substr_replace($sql," ORDER BY $order ",$tiene_limit,0);    
    }
    elseif (!$tiene_order && !$tiene_limit) {
      $sql .= " ORDER BY $order";
    }

    $this->_sql = $sql;
    return $this;
  }
  
  function add_fields($fields,$b_add = true,$b_replace=true) {
    if (!$b_add) {
      return $this;
    } 
    $sql = $this->_sql;
    if (is_array($fields)) {
      foreach ($fields as $alias => $value) {
          if (is_string($alias))
            $fields .= " $value AS $alias,";
          else
            $fields .= " $value,";
        }
        $chrs = strlen($this->_sql);
        $fields = substr_replace($fields," ", $chrs - 1);
    }

    $tiene_calc   = strpos($sql,'SQL_CALC_FOUND_ROWS');
    if ($tiene_calc) {
      $tiene_select = $tiene_calc + 19;
    }
    else {
      $tiene_select = strpos($sql,'SELECT');
      if ($tiene_select!==false) {
        $tiene_select += 6;
      }    
    }
    $tiene_from   = strpos($sql,'FROM');

    if (($tiene_select!==false) && $tiene_from) {
      
      //reemplaza los campos
      if ($b_replace) {
        $sql = substr_replace($sql,' '.$fields.' ',$tiene_select,$tiene_from-$tiene_select);
      }
      //los agrega al final
      else {
        $sql = substr_replace($sql,', '.$fields.' ',$tiene_from,0);      
      }  
    }
   
    $this->_sql = $sql;
    return $this;
  }
  
  private function get_insert($table,$fields) {

    $this->_sql = '';
    
    if (!is_array($fields)) {
      throw new Exception("fields debe ser un array");
      return false;
    }
    
    foreach($fields as $key=>$value) {
      $cols ='';
      if (is_string($value) && (strlen($value)<1)) {
        $value = "NULL";
      }
      if (is_null($value)) {
        $value = "NULL";    
      }
      elseif ($value!='NULL') {
        $value = "'$value'";
      }
      if (is_string($key)) {
        $line_1 .= "`$key`,";
      }
      $line_2 .= "$value,";
    }
    $line_1 = ereg_replace(',$','',$line_1);
    $line_2 = ereg_replace(',$','',$line_2);
    
    $this->_sql = "INSERT INTO $table ($line_1) VALUES ($line_2)";
    
    return $this;
  }
  
  private function get_select ($table, $fields) {
    $this->_sql = '';
    
    $error = null;
    if (!is_string($table)) {
      $error = "table debe ser string";
    }
    elseif (!is_string($fields)) {
      if (!is_array($fields)) {
        $error = '$fields tiene que ser array o string';
      }
      else {
      /*no hay error columns es array y table string*/
        foreach ($fields as $alias => $value) {
          if (is_string($alias))
            $str_fields .= " $value AS $alias,";
          else
            $str_fields .= " $value,";
        }
        
        $this->_sql = "SELECT $str_fields";
        $chrs = strlen($this->_sql);
        $this->_sql = substr_replace($this->_sql," ", $chrs - 1);
        $this->_sql .= "FROM $table";  
      }
    }
    else {
      /*no hay error  $columns es string y $table tambien*/
      $this->_sql = "SELECT $fields FROM $table";
    }
    if ($error !== null)
      throw new Exception($error);
    return $this;
  }
  
  private function get_update($table, $fields) {

    $this->_sql = '';

    foreach ($fields as $key=>$value) {
      if (is_null($value)) {
        $value = "NULL";    
      }
      if (is_string($value) && (strlen($value)<1)) {
        $value = "NULL";
      }
      elseif ($value!='NULL') {
        $value = "'$value'";
      }
      if ($sql) {
        $sql .= ",$key=$value"; 
      }
      else {
        $sql .= "$key=$value";        
      }
    }
    
    $this->_sql = "UPDATE $table SET $sql";

    return $this;
  }
  
  public function set_sql ($sql) {
    $this->_sql = $sql;
    return true;
  }
}  


